From e4ff05cef1b659ffdd0373e0d57b0424033b4f46 Mon Sep 17 00:00:00 2001 From: "iap10@labyrinth.cl.cam.ac.uk" Date: Thu, 27 Jan 2005 23:53:26 +0000 Subject: [PATCH] bitkeeper revision 1.1159.231.12 (41f97ef6r1c2TDcgR-o8jFV1IWm5dA) Lean decoder for MMIO instructions. Signed-off-by: Jun Nakajima Signed-off-by: Chengyuan Li Signed-off-by: ian.pratt@cl.cam.ac.uk --- .rootkeys | 1 + xen/arch/x86/vmx.c | 14 +- xen/arch/x86/vmx_io.c | 152 ++++++++ xen/arch/x86/vmx_platform.c | 554 +++++++++++++++++++++++++++++ xen/include/asm-x86/shadow.h | 9 +- xen/include/asm-x86/vmx_platform.h | 74 +++- xen/include/asm-x86/vmx_vmcs.h | 12 - 7 files changed, 799 insertions(+), 17 deletions(-) create mode 100644 xen/arch/x86/vmx_platform.c diff --git a/.rootkeys b/.rootkeys index 9f2d05bfcc..a1e6da4afc 100644 --- a/.rootkeys +++ b/.rootkeys @@ -891,6 +891,7 @@ 3ddb79bcOftONV9h4QCxXOfiT0h91w xen/arch/x86/traps.c 41c0c411tD3C7TpfDMiFTf7BaNd_Dg xen/arch/x86/vmx.c 41c0c411ODt8uEmV-yUxpQLpqimE5Q xen/arch/x86/vmx_io.c +41f97ef5139vN42cOYHfX_Ac8WOOjA xen/arch/x86/vmx_platform.c 41c0c4128URE0dxcO15JME_MuKBPfg xen/arch/x86/vmx_vmcs.c 419cbedeQDg8IrO3izo3o5rQNlo0kQ xen/arch/x86/x86_32/asm-offsets.c 3e32af9aRnYGl4GMOaDKp7JdfhOGhg xen/arch/x86/x86_32/domain_page.c diff --git a/xen/arch/x86/vmx.c b/xen/arch/x86/vmx.c index acfc14eb4c..010bccbba3 100644 --- a/xen/arch/x86/vmx.c +++ b/xen/arch/x86/vmx.c @@ -107,7 +107,7 @@ static int vmx_do_page_fault(unsigned long va, unsigned long error_code) { unsigned long eip, pfn; unsigned int index; - unsigned long gpde = 0; + unsigned long gpde = 0, gpte, gpa; int result; struct exec_domain *ed = current; struct mm_struct *m = &ed->mm; @@ -137,6 +137,15 @@ static int vmx_do_page_fault(unsigned long va, unsigned long error_code) m->guest_pl2e_cache[index] = mk_l2_pgentry((pfn << PAGE_SHIFT) | __PAGE_HYPERVISOR); } + + if (unlikely(__get_user(gpte, (unsigned long *) + &linear_pg_table[va >> PAGE_SHIFT]))) + return 0; + + gpa = (gpte & PAGE_MASK) | (va & (PAGE_SIZE - 1)); + + if (mmio_space(gpa)) + handle_mmio(va, gpte, gpa); if ((result = shadow_fault(va, error_code))) return result; @@ -283,7 +292,7 @@ static inline void guest_pl2e_cache_invalidate(struct mm_struct *m) memset(m->guest_pl2e_cache, 0, PAGE_SIZE); } -static inline unsigned long gva_to_gpa(unsigned long gva) +inline unsigned long gva_to_gpa(unsigned long gva) { unsigned long gpde, gpte, pfn, index; struct exec_domain *d = current; @@ -784,6 +793,7 @@ asmlinkage void vmx_vmexit_handler(struct xen_regs regs) __vmread(VM_EXIT_INTR_ERROR_CODE, &error_code); VMX_DBG_LOG(DBG_LEVEL_VMMU, "eax=%x, ebx=%x, ecx=%x, edx=%x, esi=%x, edi=%x\n", regs.eax, regs.ebx, regs.ecx, regs.edx, regs.esi, regs.edi); + d->thread.arch_vmx.vmx_platform.mpci.inst_decoder_regs = ®s; if (!(error = vmx_do_page_fault(va, error_code))) { /* diff --git a/xen/arch/x86/vmx_io.c b/xen/arch/x86/vmx_io.c index 85862f94ea..652bf3613d 100644 --- a/xen/arch/x86/vmx_io.c +++ b/xen/arch/x86/vmx_io.c @@ -29,8 +29,143 @@ #include #include #include +#include extern long do_block(); + +#if defined (__i386__) +static void load_xen_regs(struct xen_regs *regs) +{ + /* + * Write the guest register value into VMCS + */ + __vmwrite(GUEST_SS_SELECTOR, regs->ss); + __vmwrite(GUEST_ESP, regs->esp); + __vmwrite(GUEST_EFLAGS, regs->eflags); + __vmwrite(GUEST_CS_SELECTOR, regs->cs); + __vmwrite(GUEST_EIP, regs->eip); +} + +static void set_reg_value (int size, int index, int seg, struct xen_regs *regs, long value) +{ + switch (size) { + case BYTE: + switch (index) { + case 0: + regs->eax &= 0xFFFFFF00; + regs->eax |= (value & 0xFF); + break; + case 1: + regs->ecx &= 0xFFFFFF00; + regs->ecx |= (value & 0xFF); + break; + case 2: + regs->edx &= 0xFFFFFF00; + regs->edx |= (value & 0xFF); + break; + case 3: + regs->ebx &= 0xFFFFFF00; + regs->ebx |= (value & 0xFF); + break; + case 4: + regs->eax &= 0xFFFF00FF; + regs->eax |= ((value & 0xFF) << 8); + break; + case 5: + regs->ecx &= 0xFFFF00FF; + regs->ecx |= ((value & 0xFF) << 8); + break; + case 6: + regs->edx &= 0xFFFF00FF; + regs->edx |= ((value & 0xFF) << 8); + break; + case 7: + regs->ebx &= 0xFFFF00FF; + regs->ebx |= ((value & 0xFF) << 8); + break; + default: + printk("size:%x, index:%x are invalid!\n", size, index); + break; + + } + break; + case WORD: + switch (index) { + case 0: + regs->eax &= 0xFFFF0000; + regs->eax |= (value & 0xFFFF); + break; + case 1: + regs->ecx &= 0xFFFF0000; + regs->ecx |= (value & 0xFFFF); + break; + case 2: + regs->edx &= 0xFFFF0000; + regs->edx |= (value & 0xFFFF); + break; + case 3: + regs->ebx &= 0xFFFF0000; + regs->ebx |= (value & 0xFFFF); + break; + case 4: + regs->esp &= 0xFFFF0000; + regs->esp |= (value & 0xFFFF); + break; + + case 5: + regs->ebp &= 0xFFFF0000; + regs->ebp |= (value & 0xFFFF); + break; + case 6: + regs->esi &= 0xFFFF0000; + regs->esi |= (value & 0xFFFF); + break; + case 7: + regs->edi &= 0xFFFF0000; + regs->edi |= (value & 0xFFFF); + break; + default: + printk("size:%x, index:%x are invalid!\n", size, index); + break; + } + break; + case LONG: + switch (index) { + case 0: + regs->eax = value; + break; + case 1: + regs->ecx = value; + break; + case 2: + regs->edx = value; + break; + case 3: + regs->ebx = value; + break; + case 4: + regs->esp = value; + break; + case 5: + regs->ebp = value; + break; + case 6: + regs->esi = value; + break; + case 7: + regs->edi = value; + break; + default: + printk("size:%x, index:%x are invalid!\n", size, index); + break; + } + break; + default: + printk("size:%x, index:%x are invalid!\n", size, index); + break; + } +} +#endif void vmx_io_assist(struct exec_domain *ed) { @@ -40,6 +175,11 @@ void vmx_io_assist(struct exec_domain *ed) execution_context_t *ec = get_execution_context(); unsigned long old_eax; int sign; + struct mi_per_cpu_info *mpci_p; + struct xen_regs *inst_decoder_regs; + + mpci_p = &ed->thread.arch_vmx.vmx_platform.mpci; + inst_decoder_regs = mpci_p->inst_decoder_regs; /* clear the pending event */ ed->vcpu_info->evtchn_upcall_pending = 0; @@ -76,7 +216,19 @@ void vmx_io_assist(struct exec_domain *ed) if (p->dir == IOREQ_WRITE) { return; } + int size = -1, index = -1; + + size = operand_size(ed->thread.arch_vmx.vmx_platform.mpci.mmio_target); + index = operand_index(ed->thread.arch_vmx.vmx_platform.mpci.mmio_target); + + if (ed->thread.arch_vmx.vmx_platform.mpci.mmio_target & WZEROEXTEND) { + p->u.data = p->u.data & 0xffff; + } + set_reg_value(size, index, 0, (struct xen_regs *)ec, p->u.data); + } + load_xen_regs((struct xen_regs *)ec); + return; } if (p->dir == IOREQ_WRITE) { diff --git a/xen/arch/x86/vmx_platform.c b/xen/arch/x86/vmx_platform.c new file mode 100644 index 0000000000..9ee99cd227 --- /dev/null +++ b/xen/arch/x86/vmx_platform.c @@ -0,0 +1,554 @@ +/* + * vmx_platform.c: handling x86 platform related MMIO instructions + * Copyright (c) 2004, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define DECODE_success 1 +#define DECODE_failure 0 + +#if defined (__x86_64__) +static void store_xen_regs(struct xen_regs *regs) +{ + +} + +static long get_reg_value(int size, int index, int seg, struct xen_regs *regs) +{ + return 0; +} +#elif defined (__i386__) +static void store_xen_regs(struct xen_regs *regs) +{ + __vmread(GUEST_SS_SELECTOR, ®s->ss); + __vmread(GUEST_ESP, ®s->esp); + __vmread(GUEST_EFLAGS, ®s->eflags); + __vmread(GUEST_CS_SELECTOR, ®s->cs); + __vmread(GUEST_EIP, ®s->eip); +} + +static long get_reg_value(int size, int index, int seg, struct xen_regs *regs) +{ + /* + * Reference the db_reg[] table + */ + switch (size) { + case BYTE: + switch (index) { + case 0: //%al + return (char)(regs->eax & 0xFF); + case 1: //%cl + return (char)(regs->ecx & 0xFF); + case 2: //%dl + return (char)(regs->edx & 0xFF); + case 3: //%bl + return (char)(regs->ebx & 0xFF); + case 4: //%ah + return (char)((regs->eax & 0xFF00) >> 8); + case 5: //%ch + return (char)((regs->ecx & 0xFF00) >> 8); + case 6: //%dh + return (char)((regs->edx & 0xFF00) >> 8); + case 7: //%bh + return (char)((regs->ebx & 0xFF00) >> 8); + default: + printk("(get_reg_value)size case 0 error\n"); + return -1; + } + case WORD: + switch (index) { + case 0: //%ax + return (short)(regs->eax & 0xFFFF); + case 1: //%cx + return (short)(regs->ecx & 0xFFFF); + case 2: //%dx + return (short)(regs->edx & 0xFFFF); + case 3: //%bx + return (short)(regs->ebx & 0xFFFF); + case 4: //%sp + return (short)(regs->esp & 0xFFFF); + break; + case 5: //%bp + return (short)(regs->ebp & 0xFFFF); + case 6: //%si + return (short)(regs->esi & 0xFFFF); + case 7: //%di + return (short)(regs->edi & 0xFFFF); + default: + printk("(get_reg_value)size case 1 error\n"); + return -1; + } + case LONG: + switch (index) { + case 0: //%eax + return regs->eax; + case 1: //%ecx + return regs->ecx; + case 2: //%edx + return regs->edx; + + case 3: //%ebx + return regs->ebx; + case 4: //%esp + return regs->esp; + case 5: //%ebp + return regs->ebp; + case 6: //%esi + return regs->esi; + case 7: //%edi + return regs->edi; + default: + printk("(get_reg_value)size case 2 error\n"); + return -1; + } + default: + printk("(get_reg_value)size case error\n"); + return -1; + } +} +#endif + +static inline unsigned char *check_prefix(unsigned char *inst, struct instruction *thread_inst) +{ + while (1) { + switch (*inst) { + case 0xf3: //REPZ + case 0xf2: //REPNZ + case 0xf0: //LOCK + case 0x2e: //CS + case 0x36: //SS + case 0x3e: //DS + case 0x26: //ES + case 0x64: //FS + case 0x65: //GS + break; + case 0x66: //32bit->16bit + thread_inst->op_size = WORD; + break; + case 0x67: + break; + default: + return inst; + } + inst++; + } +} + +static inline unsigned long get_immediate(const unsigned char *inst, int op_size) +{ + int mod, reg, rm; + unsigned long val = 0; + int i; + + mod = (*inst >> 6) & 3; + reg = (*inst >> 3) & 7; + rm = *inst & 7; + + inst++; //skip ModR/M byte + if (mod != 3 && rm == 4) { + inst++; //skip SIB byte + } + + switch(mod) { + case 0: + if (rm == 5) { + inst = inst + 4; //disp32, skip 4 bytes + } + break; + case 1: + inst++; //disp8, skip 1 byte + break; + case 2: + inst = inst + 4; //disp32, skip 4 bytes + } + for (i = 0; i < op_size; i++) { + val |= (*inst++ & 0xff) << (8 * i); + } + + return val; +} + +static inline int get_index(const unsigned char *inst) +{ + int mod, reg, rm; + + mod = (*inst >> 6) & 3; + reg = (*inst >> 3) & 7; + rm = *inst & 7; + + //Only one operand in the instruction is register + if (mod == 3) { + return rm; + } else { + return reg; + } + return 0; +} + +static int vmx_decode(const unsigned char *inst, struct instruction *thread_inst) +{ + int index; + + switch(*inst) { + case 0x88: + /* mov r8 to m8 */ + thread_inst->op_size = BYTE; + index = get_index((inst + 1)); + thread_inst->operand[0] = mk_operand(BYTE, index, 0, REGISTER); + break; + case 0x89: + /* mov r32/16 to m32/16 */ + index = get_index((inst + 1)); + if (thread_inst->op_size == WORD) { + thread_inst->operand[0] = mk_operand(WORD, index, 0, REGISTER); + } else { + thread_inst->op_size = LONG; + thread_inst->operand[0] = mk_operand(LONG, index, 0, REGISTER); + } + break; + case 0x8a: + /* mov m8 to r8 */ + thread_inst->op_size = BYTE; + index = get_index((inst + 1)); + thread_inst->operand[1] = mk_operand(BYTE, index, 0, REGISTER); + break; + case 0x8b: + /* mov r32/16 to m32/16 */ + index = get_index((inst + 1)); + if (thread_inst->op_size == WORD) { + thread_inst->operand[1] = mk_operand(WORD, index, 0, REGISTER); + } else { + thread_inst->op_size = LONG; + thread_inst->operand[1] = mk_operand(LONG, index, 0, REGISTER); + } + break; + case 0x8c: + case 0x8e: + printk("%x, This opcode hasn't been handled yet!", *inst); + return DECODE_failure; + /* Not handle it yet. */ + + case 0xa0: + /* mov byte to al */ + thread_inst->op_size = BYTE; + thread_inst->operand[1] = mk_operand(BYTE, 0, 0, REGISTER); + break; + case 0xa1: + /* mov word/doubleword to ax/eax */ + if (thread_inst->op_size == WORD) { + thread_inst->operand[1] = mk_operand(WORD, 0, 0, REGISTER); + } else { + thread_inst->op_size = LONG; + thread_inst->operand[1] = mk_operand(LONG, 0, 0, REGISTER); + } + break; + case 0xa2: + /* mov al to (seg:offset) */ + thread_inst->op_size = BYTE; + thread_inst->operand[0] = mk_operand(BYTE, 0, 0, REGISTER); + break; + case 0xa3: + /* mov ax/eax to (seg:offset) */ + if (thread_inst->op_size == WORD) { + thread_inst->operand[0] = mk_operand(WORD, 0, 0, REGISTER); + } else { + thread_inst->op_size = LONG; + thread_inst->operand[0] = mk_operand(LONG, 0, 0, REGISTER); + } + break; + case 0xa4: + /* movsb */ + thread_inst->op_size = BYTE; + strcpy(thread_inst->i_name, "movs"); + + return DECODE_success; + case 0xa5: + /* movsw/movsl */ + if (thread_inst->op_size == WORD) { + } else { + thread_inst->op_size = LONG; + } + + strcpy(thread_inst->i_name, "movs"); + + return DECODE_success; + + case 0xc6: + /* mov imm8 to m8 */ + thread_inst->op_size = BYTE; + thread_inst->operand[0] = mk_operand(BYTE, 0, 0, IMMEDIATE); + thread_inst->immediate = get_immediate((inst+1), thread_inst->op_size); + break; + case 0xc7: + /* mov imm16/32 to m16/32 */ + if (thread_inst->op_size == WORD) { + thread_inst->operand[0] = mk_operand(WORD, 0, 0, IMMEDIATE); + } else { + thread_inst->op_size = LONG; + thread_inst->operand[0] = mk_operand(LONG, 0, 0, IMMEDIATE); + } + thread_inst->immediate = get_immediate((inst+1), thread_inst->op_size); + break; + + case 0x0f: + break; + default: + printk("%x, This opcode hasn't been handled yet!", *inst); + return DECODE_failure; + } + + strcpy(thread_inst->i_name, "mov"); + if (*inst != 0x0f) { + return DECODE_success; + } + + inst++; + switch (*inst) { + + /* movz */ + case 0xb7: + index = get_index((inst + 1)); + thread_inst->operand[1] = mk_operand(LONG, index, 0, REGISTER); + strcpy(thread_inst->i_name, "movzw"); + + return DECODE_success; + default: + printk("0f %x, This opcode hasn't been handled yet!", *inst); + return DECODE_failure; + } + + /* will never reach here */ + return DECODE_failure; +} + +static int inst_copy_from_guest(char *buf, unsigned long guest_eip, int inst_len) +{ + unsigned long gpte; + unsigned long mfn; + unsigned long ma; + unsigned char * inst_start; + + if (inst_len > MAX_INST_LEN || inst_len <= 0) { + return 0; + } + + if ((guest_eip & PAGE_MASK) == ((guest_eip + inst_len) & PAGE_MASK)) { + if ( unlikely(__get_user(gpte, (unsigned long *) + &linear_pg_table[guest_eip >> PAGE_SHIFT])) ) + { + printk("inst_copy_from_guest- EXIT: read gpte faulted" ); + return 0; + } + mfn = phys_to_machine_mapping[gpte >> PAGE_SHIFT]; + ma = (mfn << PAGE_SHIFT) | (guest_eip & (PAGE_SIZE - 1)); + inst_start = (unsigned char *)map_domain_mem(ma); + + strncpy(buf, inst_start, inst_len); + unmap_domain_mem(inst_start); + } else { + // Todo: In two page frames + } + + return inst_len; +} + +static void init_instruction(struct instruction *mmio_inst) +{ + memset(mmio_inst->i_name, '0', I_NAME_LEN); + mmio_inst->op_size = 0; + mmio_inst->offset = 0; + mmio_inst->immediate = 0; + mmio_inst->seg_sel = 0; + mmio_inst->op_num = 0; + + mmio_inst->operand[0] = 0; + mmio_inst->operand[1] = 0; + mmio_inst->operand[2] = 0; + + mmio_inst->flags = 0; +} + +static int read_from_mmio(struct instruction *inst_p) +{ + // Only for mov instruction now!!! + if (inst_p->operand[1] & REGISTER) + return 1; + + return 0; +} + +// dir: 1 read from mmio +// 0 write to mmio +static void send_mmio_req(unsigned long gpa, + struct instruction *inst_p, long value, int dir, int pvalid) +{ + struct exec_domain *d = current; + vcpu_iodata_t *vio; + ioreq_t *p; + struct mi_per_cpu_info *mpci_p; + struct xen_regs *inst_decoder_regs; + extern inline unsigned long gva_to_gpa(unsigned long gva); + extern long evtchn_send(int lport); + extern long do_block(void); + + mpci_p = ¤t->thread.arch_vmx.vmx_platform.mpci; + inst_decoder_regs = mpci_p->inst_decoder_regs; + vio = (vcpu_iodata_t *) d->thread.arch_vmx.vmx_platform.shared_page_va; + + if (vio == NULL) { + printk("bad shared page\n"); + domain_crash(); + } + p = &vio->vp_ioreq; + + set_bit(ARCH_VMX_IO_WAIT, &d->thread.arch_vmx.flags); + p->dir = dir; + p->pdata_valid = pvalid; + p->count = 1; + + p->port_mm = 1; + p->size = inst_p->op_size; + p->addr = gpa; + p->u.data = value; + + // p->state = STATE_UPSTREAM_SENDING; + p->state = STATE_IOREQ_READY; + + // Try to use ins/outs' framework + if (pvalid) { + // Handle "movs" + p->u.pdata = (void *) ((p->dir == IOREQ_WRITE) ? + inst_decoder_regs->esi + : inst_decoder_regs->edi); + p->u.pdata = (void *) gva_to_gpa(p->u.data); + p->count = inst_decoder_regs->ecx; + inst_decoder_regs->ecx = 0; + p->df = (inst_decoder_regs->eflags & EF_DF) ? 1 : 0; + } + + evtchn_send(IOPACKET_PORT); + do_block(); + +} + +void handle_mmio(unsigned long va, unsigned long gpte, unsigned long gpa) +{ + unsigned long eip; + unsigned long inst_len; + struct mi_per_cpu_info *mpci_p; + struct xen_regs *inst_decoder_regs; + struct instruction mmio_inst; + unsigned char inst[MAX_INST_LEN]; + int ret; + + mpci_p = ¤t->thread.arch_vmx.vmx_platform.mpci; + inst_decoder_regs = mpci_p->inst_decoder_regs; + + __vmread(GUEST_EIP, &eip); + __vmread(INSTRUCTION_LEN, &inst_len); + + memset(inst, '0', MAX_INST_LEN); + ret = inst_copy_from_guest(inst, eip, inst_len); + if (ret != inst_len) { + printk("handle_mmio - EXIT: get guest instruction fault\n"); + domain_crash(); + } + + init_instruction(&mmio_inst); + + if (vmx_decode(check_prefix(inst, &mmio_inst), &mmio_inst) == DECODE_failure) + domain_crash(); + + __vmwrite(GUEST_EIP, eip + inst_len); + store_xen_regs(inst_decoder_regs); + + // Only handle "mov" and "movs" instructions! + if (!strncmp(mmio_inst.i_name, "movzw", 5)) { + long value = 0; + int index; + + if (read_from_mmio(&mmio_inst)) { + // Send the request and waiting for return value. + mpci_p->mmio_target = mmio_inst.operand[1] | WZEROEXTEND; + mmio_inst.op_size = WORD; + send_mmio_req(gpa, &mmio_inst, value, 1, 0); + } else { + // Write to MMIO + if (mmio_inst.operand[0] & IMMEDIATE) { + value = mmio_inst.immediate; + } else if (mmio_inst.operand[0] & REGISTER) { + index = operand_index(mmio_inst.operand[0]); + value = get_reg_value(WORD, index, 0, inst_decoder_regs); + } else { + domain_crash(); + } + mmio_inst.op_size = WORD; + send_mmio_req(gpa, &mmio_inst, value, 0, 0); + return; + } + } + + if (!strncmp(mmio_inst.i_name, "movs", 4)) { + int tmp_dir; + + tmp_dir = ((va == inst_decoder_regs->edi) ? IOREQ_WRITE : IOREQ_READ); + send_mmio_req(gpa, &mmio_inst, 0, tmp_dir, 1); + return; + } + + if (!strncmp(mmio_inst.i_name, "mov", 3)) { + long value = 0; + int size, index; + + if (read_from_mmio(&mmio_inst)) { + // Send the request and waiting for return value. + mpci_p->mmio_target = mmio_inst.operand[1]; + send_mmio_req(gpa, &mmio_inst, value, 1, 0); + } else { + // Write to MMIO + if (mmio_inst.operand[0] & IMMEDIATE) { + value = mmio_inst.immediate; + } else if (mmio_inst.operand[0] & REGISTER) { + size = operand_size(mmio_inst.operand[0]); + index = operand_index(mmio_inst.operand[0]); + value = get_reg_value(size, index, 0, inst_decoder_regs); + } else { + domain_crash(); + } + send_mmio_req(gpa, &mmio_inst, value, 0, 0); + return; + } + domain_crash(); + } + domain_crash(); +} + diff --git a/xen/include/asm-x86/shadow.h b/xen/include/asm-x86/shadow.h index b22215688e..37ad49b7fa 100644 --- a/xen/include/asm-x86/shadow.h +++ b/xen/include/asm-x86/shadow.h @@ -305,10 +305,15 @@ static inline void l1pte_propagate_from_guest( case SHM_full_32: { unsigned long host_pfn, host_gpte; + spte = 0; + + if (mmio_space(gpte & 0xFFFFF000)) { + *spte_p = spte; + return; + } host_pfn = phys_to_machine_mapping[gpte >> PAGE_SHIFT]; host_gpte = (host_pfn << PAGE_SHIFT) | (gpte & ~PAGE_MASK); - spte = 0; if ( (host_gpte & (_PAGE_PRESENT|_PAGE_ACCESSED) ) == (_PAGE_PRESENT|_PAGE_ACCESSED) ) @@ -697,7 +702,7 @@ static inline void __shadow_mk_pagetable( struct mm_struct *mm ) SH_VVLOG("__shadow_mk_pagetable(guest_gpfn=%08lx, gpfn=%08lx\n", guest_gpfn, gpfn); - spfn = __shadow_status(mm, gpfn) & PSH_pfn_mask; + spfn = __shadow_status(mm, guest_gpfn) & PSH_pfn_mask; if ( unlikely(spfn == 0) ) { spfn = shadow_l2_table(mm, gpfn); mm->shadow_table = mk_pagetable(spfn< /* from Linux */ +#include /* from Linux */ + +#define MAX_OPERAND_NUM 3 +#define I_NAME_LEN 16 + +#define mk_operand(size, index, seg, flag) \ + (((size) << 24) | ((index) << 16) | ((seg) << 8) | (flag)) + +#define operand_size(operand) \ + ((operand >> 24) & 0xFF) + +#define operand_index(operand) \ + ((operand >> 16) & 0xFF) + //For instruction.operand[].size +#define BYTE 1 +#define WORD 2 +#define LONG 4 +#define QUAD 8 + + //For instruction.operand[].flag +#define REGISTER 0x1 +#define MEMORY 0x2 +#define IMMEDIATE 0x4 +#define WZEROEXTEND 0x8 + + //For instruction.flags +#define REPZ 0x1 +#define REPNZ 0x2 + +struct instruction { + __s8 i_name[I_NAME_LEN]; //Instruction's name + __s16 op_size; //The operand's bit size, e.g. 16-bit or 32-bit. + + __u64 offset; //The effective address + //offset = Base + (Index * Scale) + Displacement + + __u64 immediate; + + __u16 seg_sel; //Segmentation selector + + __u32 operand[MAX_OPERAND_NUM]; //The order of operand is from AT&T Assembly + __s16 op_num; //The operand numbers + + __u32 flags; // +}; + +#define VGA_SPACE_START 0xA0000 +#define VGA_SPACE_END 0xC0000 +#define MAX_INST_LEN 32 + +struct mi_per_cpu_info +{ + unsigned long mmio_target; + struct xen_regs *inst_decoder_regs; +}; + +struct virutal_platform_def { + unsigned long *real_mode_data; /* E820, etc. */ + unsigned long shared_page_va; + struct mi_per_cpu_info mpci; /* MMIO */ +}; + +extern int mmio_space(unsigned long); +extern void handle_mmio(unsigned long, unsigned long, unsigned long); +extern int vmx_setup_platform(struct exec_domain *, execution_context_t *); + +extern inline int mmio_space(unsigned long gpa) +{ + if (gpa >= VGA_SPACE_START && gpa < VGA_SPACE_END) { + return 1; + } + return 0; +} #endif diff --git a/xen/include/asm-x86/vmx_vmcs.h b/xen/include/asm-x86/vmx_vmcs.h index 8ec77d8ed5..40d315d609 100644 --- a/xen/include/asm-x86/vmx_vmcs.h +++ b/xen/include/asm-x86/vmx_vmcs.h @@ -39,15 +39,7 @@ union vmcs_arbytes { unsigned int bytes; }; -struct virutal_platform_def { - unsigned long *real_mode_data; /* E820, etc. */ - unsigned long shared_page_va; -}; - -int vmx_setup_platform(struct exec_domain *, execution_context_t *); - #define VMX_CPU_STATE_PG_ENABLED 0 - #define VMCS_SIZE 0x1000 struct vmcs_struct { @@ -62,10 +54,6 @@ struct arch_vmx_struct { unsigned long cpu_cr3; unsigned long cpu_state; struct virutal_platform_def vmx_platform; -#if 0 - /* open */ - unsigned long *page_list; /* page list for MMIO */ -#endif }; #define vmx_schedule_tail(next) \ -- 2.30.2